#include "sportstate.h"

#include "lvgl.h"

#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <cmath>

#define CALORIC_CORFFICIENT 0.5f

#define PI 3.1415926535897932384626433832795f
#define HALF_PI 1.5707963267948966192313216916398f
#define TWO_PI 6.283185307179586476925286766559f
#define DEG_TO_RAD 0.017453292519943295769236907684886f
#define RAD_TO_DEG 57.295779513082320876798154814105f
#define EULER 2.718281828459045235360287471352f

#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x))

static double distanceBetween(double lat1, double long1, double lat2, double long2);


static double distanceBetween(double lat1, double long1, double lat2, double long2)
{
    // returns distance in meters between two positions, both specified
    // as signed decimal-degrees latitude and longitude. Uses great-circle
    // distance computation for hypothetical sphere of radius 6372795 meters.
    // Because Earth is no exact sphere, rounding errors may be up to 0.5%.
    // Courtesy of Maarten Lamers
    double delta = radians(long1 - long2);
    double sdlong = sin(delta);
    double cdlong = cos(delta);
    lat1 = radians(lat1);
    lat2 = radians(lat2);
    double slat1 = sin(lat1);
    double clat1 = cos(lat1);
    double slat2 = sin(lat2);
    double clat2 = cos(lat2);
    delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
    delta = sq(delta);
    delta += sq(clat2 * sdlong);
    delta = sqrt(delta);
    double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
    delta = atan2(delta, denom);
    return delta * 6372795;
}


static double sport_status_get_distance_offset(gps_info_t* gpsInfo)
{
    static bool isFirst = true;
    static double preLongitude;
    static double preLatitude;

    double offset = 0.0f;

    if (!isFirst)
    {
				offset = distanceBetween(gpsInfo->latitude, gpsInfo->longitude, preLatitude, preLongitude);
    }
    else
    {
        isFirst = false;
    }

    preLongitude = gpsInfo->longitude;
    preLatitude = gpsInfo->latitude;

    return offset;
}


sport_status_info_t sport_status_update(gps_info_t *gpsInfo)
{
		sport_status_info_t sportStatus;
	
    uint32_t timeElaps = lv_tick_elaps(sportStatus.lastTick);

    float speedKph = 0.0f;
    bool isSignalInterruption = (gpsInfo->isVaild && (gpsInfo->satellites == 0));

    if (gpsInfo->satellites >= 3)
    {
        float spd = gpsInfo->speed;
        speedKph = spd > 1 ? spd : 0;
    }

    if (speedKph > 0.0f || isSignalInterruption)
    {
        sportStatus.singleTime += timeElaps;
        sportStatus.totalTime += timeElaps;

        if (speedKph > 0.0f)
        {
            float dist = (float)sport_status_get_distance_offset(gpsInfo);

            sportStatus.singleDistance += dist;
            sportStatus.totalDistance += dist;

            float meterPerSec = sportStatus.singleDistance * 1000 / sportStatus.singleTime;
            sportStatus.speedAvgKph = meterPerSec * 3.6f;

            if (speedKph > sportStatus.speedMaxKph)
            {
                sportStatus.speedMaxKph = speedKph;
            }

            float calorie = speedKph * sportStatus.weight * CALORIC_CORFFICIENT * timeElaps / 1000 / 3600;
            sportStatus.singleCalorie += calorie;
        }
    }

    sportStatus.speedKph = speedKph;

    sportStatus.lastTick = (uint64_t)lv_tick_get();
		printf("-----sportStatus.lastTick = %d",sportStatus.lastTick);
		printf("-----sportStatus.singleTime = %llu",sportStatus.singleTime);
		
		return sportStatus;
}

